package com.zzf.concurrent.example.lock.custom;

import com.zzf.concurrent.example.lock.exception.TimeoutException;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 *
 * @author GaoFeng2017
 * @date 2019/8/7 8:47
 */
@Slf4j
public class BooleanLock {

    private List<Thread> threads;
    private boolean isLocked;
    private Thread thread;


    public BooleanLock() {
        threads = new ArrayList<>();
        isLocked = false;
    }

    public synchronized void lock() {

        while(isLocked) {
            threads.add(Thread.currentThread());
            log.info("thread size is {}", this.getThreadSize());
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        this.isLocked = true;
        Thread currentThread = Thread.currentThread();
        threads.remove(currentThread);
        log.info("{} is get lock.", currentThread.getName());
        this.thread = currentThread;

    }



    public synchronized void lock(long ms) throws TimeoutException {

        if (ms <= 0) {
            this.lock();
        }

        long endTime = System.currentTimeMillis() + ms;
        while (this.isLocked) {

            // 可能会存在多次添加
            Thread currentThread = Thread.currentThread();
            threads.add(currentThread);
            log.info("thread size is {}", this.getThreadSize());

            try {
                this.wait(ms);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (System.currentTimeMillis() - endTime >= 0) {
                // 超时处理
                threads.remove(currentThread);
                throw new TimeoutException();
            }

        }

        Thread currentThread = Thread.currentThread();
        threads.remove(currentThread);
        this.isLocked = true;
        log.info("{} is get lock.", currentThread.getName());
    }

    public synchronized void unlock() {
        Thread currentThread = Thread.currentThread();

        if (this.thread != currentThread) {
            log.info("thread not match");
            return;
        }

        this.notifyAll();
        this.isLocked = false;
        log.info("{} release lock, thread size is {}.", currentThread.getName(), this.getThreadSize());
    }

    public List<Thread> getThreadList() {
        return Collections.unmodifiableList(threads);
    }

    public int getThreadSize() {
        return this.threads.size();
    }
}
